#!/usr/bin/python
# -*- coding: utf-8 -*-
'''
@date: 2011-11-12
@author: shell.xu
'''
import os, sys, fcntl
import time, signal

def daemonized():
    try:
        if os.fork() > 0: sys.exit(0)
    except OSError: sys.exit(1)
    os.chdir("/")
    os.setsid()
    os.umask(0)
    for i in xrange(0, 3): os.close(i)
    try:
        if os.fork() > 0: sys.exit(0)
    except OSError: sys.exit(1)

class runfile(object):

    def __init__(self, fpath):
        self.fpath = fpath

    def __enter__(self): self.acquire()
    def __exit__(self, type, value, traceback): self.release()

    def chk_state(self, in_run):
        if in_run ^ path.exists(self.fpath):
            raise Exception('runfile exist status error.')

    def getpid(self):
        self.chk_state(True)
        with open(self.fpath, 'r') as f: return f.read().strip()

    def acquire(self):
        self.chk_state(False)
        with open(self.fpath, 'w') as f: f.write(str(os.getpid()))

    def release(self):
        if int(self.getpid()) != os.getpid():
            raise Exception('runfile is not created by current process.')
        os.remove(self.fpath)

class lockfile(object):

    def __init__(self, filename, share = False):
        self.filename = filename
        self.share = fcntl.LOCK_SH if share else fcntl.LOCK_EX

    def __enter__(self):
        self.fileno = os.open(self.filename, os.O_RDONLY | os.O_CREAT | os.O_EXCL)
        fcntl.flock(self.fileno, self.share)

    def __exit__(self, type, value, traceback):
        fcntl.flock(self.fileno, fcntl.LOCK_UN)
        os.close(self.fileno)
        os.remove(self.filename)

def fork_worker(func):
    pid = os.fork()
    if pid == 0:
        func()
        sys.exit(0)
    else: return pid

def supervistor(wnum, worker):
    clean_flag = False
    pids = [fork_worker(worker) for i in xrange(wnum)]
    def clean_up(signum, frame):
        if signum != signal.SIGTERM: return
        clean_flag = True
        for pid in pids: os.kill(pid, signal.SIGTERM)
    signal.signal(signal.SIGTERM, clean_up)
    while True:
        pid = os.wait()[0]
        if clean_flag: break
        if pid not in pids: continue
        pids.remove(pid)
        pids.append(fork_worker(worker))
        time.sleep(1)
    sys.exit(0)
